
#include "Http_Lib.h"
#include "String_Manip.h"
#include <stdio.h>
#include <windows.h>



extern range h_range;
extern int already_write_size;
extern HANDLE hGlobalWaitEvent;
extern int file_size;

int Connect(const char* server_name, int port, SOCKET* connect_socket)
{
	int retval;
	unsigned int addr;
	struct sockaddr_in server;
	struct hostent *hp;
	WSADATA wsaData;
	SOCKET conn_socket;

	if((retval = WSAStartup(0x202,&wsaData))!=0)
	{
        fprintf(stderr,"WSAStartup failed with error %d\n",retval);
        WSACleanup();
        return -1;
    }

	if(port == 0)
		printf("no port specified, default port 80 will be used\n");

	if(isalpha(server_name[0]))
		hp = gethostbyname(server_name);
	else
	{
		addr = inet_addr(server_name);
		hp = gethostbyaddr((char*)&addr,4,AF_INET);
	}

    if (hp == NULL ) 
	{
        fprintf(stderr,"Client: Cannot resolve address [%s]: Error %d\n",server_name,WSAGetLastError());
        WSACleanup();
        return -2;
    }
	memset(&server,0,sizeof(server));
	memcpy(&(server.sin_addr),hp->h_addr_list[0],hp->h_length);
	server.sin_family = hp->h_addrtype;
	server.sin_port = htons(port?port:DEFAULT_PORT);

	conn_socket = socket(AF_INET,DEFAULT_PROTO,0);
	if(conn_socket < 0)
	{
	    fprintf(stderr,"Client: Error Opening socket: Error %d\n",WSAGetLastError());
        WSACleanup();
        return -1;
    }
	printf("Client connecting to: %s\n",hp->h_name);
	if( connect(conn_socket,(struct sockaddr*)&server,sizeof(server))==SOCKET_ERROR)
	{
		fprintf(stderr,"Connecting Error: %d\n",WSAGetLastError());
        WSACleanup();
        return -1;
    }
	*connect_socket = conn_socket;
	printf("%s connected\n",hp->h_name);
	return 0;
}

int HttpParse(char* response, int recv_len, SOCKET conn_socket, const char* filename, HANDLE fHandle, PMYDATA pData)
{
	char* start;
	char* buffer_sent;
	char* buffer_word;
	int resp_num, is_partial = 0;
	int body_to_write, retval, already_write=0;

	start = response;
	buffer_sent = (char*)GetSentence(&response);
	printf("%s\n",buffer_sent);
	buffer_word = (char*)GetWord(&buffer_sent);
	buffer_word = (char*)GetWord(&buffer_sent);
	resp_num = atoi(buffer_word);
	switch(resp_num)
	{
	case 200:	//OK
		break;
	case 206:	//partial
		break;
	case 400:	//Bad Request
		printf("Bad Request\n");
		return -1;
	default:
		printf("status-code is %d, disposal is required\n",resp_num);
		return -1;
	}

	for(;;)
	{
		buffer_sent = (char*) GetSentence(&response);
		printf("%s\n",buffer_sent);
		if(!strcmp(buffer_sent,"\r"))
			break;
		buffer_word = (char*) GetWord(&buffer_sent);
		if(!strcmp(buffer_word,"Content-Length:"))
			file_size = atoi(buffer_sent);
	}
	if(pData->h_index == 0)
		h_range.end[0] = file_size;
	body_to_write = recv_len -(response-start);		//compute the length of the body following the header
	retval = WriteToFile(filename, file_size, body_to_write, conn_socket, response, fHandle, pData);
	return retval?-1:0;
}

int WriteToFile(const char* filename, int cont_len, int body_to_write, SOCKET conn_socket,char* response, HANDLE fHandle, PMYDATA pData)
{
	char buffer[65536];
	int already_write,write;
	already_write = 0;
	if(body_to_write > 0)
	{
		WriteFile(fHandle,response,body_to_write,&write,NULL);
		if(write < body_to_write)
		{
			printf("some error occurs when writting to file\n");
			CloseHandle(fHandle);
			return -1;
		}
		already_write += body_to_write;
	}
	
	already_write_size = 2*already_write;
	if(pData->h_index == 0)
		SetEvent(hGlobalWaitEvent);
	printf("Thread[0]'s start is %d, end is %d\n",h_range.start[0],h_range.end[0]);
	printf("Thread[1]'s start is %d, end is %d\n",h_range.start[1],h_range.end[1]);
	while(already_write < h_range.end[pData->h_index]-h_range.start[pData->h_index])
	{
		body_to_write = recv(conn_socket,buffer,65535,0);
		if(body_to_write == SOCKET_ERROR)
		{
			printf("in Thread[%d],some error occurs when receiving left portion of the body\n",pData->h_index);
			printf("Error: %d\n",GetLastError());
			CloseHandle(fHandle);
			return -1;
		}
		WriteFile(fHandle,buffer,body_to_write,&write,NULL);
		if(write < body_to_write)
		{
			printf("in Thread[%d], some error occurs when writting to file\n",pData->h_index);
			printf("%Error: d\n",GetLastError());
			CloseHandle(fHandle);
			return -1;
		}
		already_write+=body_to_write;

	}
	printf("Thread %d finished\n",pData->h_index);
	CloseHandle(fHandle);
	return 0;
}
int HttpGet(void* lp)
{
	SOCKET conn_socket;
	int retval, cur_len;
	char buffer[65536];
	char* cur_pos;
	char* file_name;
	WCHAR w_file_name[1024];
	HANDLE fHandle;
	PMYDATA pData = (PMYDATA)lp;

	retval = Connect(pData->server_name,pData->port,&conn_socket);
	if(retval != 0)
	{
		printf("Connect() failed: %d\n",retval);
		return -1;
	}
	
	file_name = (char*) GetFilename(pData->fullpathname);
	swprintf(w_file_name,1024,L"%S%S",pData->storepathname,file_name);
	
	if((fHandle = CreateFile(w_file_name,\
							GENERIC_WRITE,\
							FILE_SHARE_WRITE,\
							NULL,OPEN_ALWAYS,\
							FILE_ATTRIBUTE_NORMAL,\
							NULL))==INVALID_HANDLE_VALUE) 
	{
		printf("Error in CreateFile: %d\n",GetLastError());
		return -1;
	}

	SetFilePointer(fHandle,h_range.start[pData->h_index],NULL,FILE_BEGIN);

	if(pData->h_index == 0)
		sprintf(buffer,"GET %s HTTP/1.0\r\nHost: %s\r\nAccept:\
					   */*\r\nConnection: close\r\n\n",\
					   pData->fullpathname,\
					   pData->server_name);
	else
		sprintf(buffer,"GET %s HTTP/1.0\r\nHost: %s\r\nAccept:\
					   */*\r\nRange: bytes=%d-\r\nConnection: close\r\n\n",\
					   pData->fullpathname,\
					   pData->server_name,\
					   h_range.start[pData->h_index]);

	printf("%s\n",buffer);

	cur_len = (int)strlen(buffer);
	cur_pos = buffer;
	retval = send(conn_socket,buffer,cur_len,0);
	while(retval < cur_len)
	{
		cur_pos += retval;
		cur_len -= retval;
		retval = send(conn_socket,cur_pos,cur_len,0);
	}

	retval = recv(conn_socket,buffer,65535,0);	//get response
	if(retval > 0)
		HttpParse(buffer, retval, conn_socket, file_name, fHandle, pData);	//parse response
	return 0;

}